/**
**************************************************************************************
*Palisma - Secrets of the Illuminati is an open-source 2D RPG                        *
*Copyright (C) 2006, Tony Sparks                                                     *
*                                                                                    *
*This library is free software; you can redistribute it and/or                       *
*modify it under the terms of the GNU Lesser General Public                          *
*License as published by the Free Software Foundation; either                        *
*version 2.1 of the License, or (at your option) any later version.                  *
*                                                                                    *
*This library is distributed in the hope that it will be useful,                     *
*but WITHOUT ANY WARRANTY; without even the implied warranty of                      *
*MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU                   *
*Lesser General Public License for more details.                                     *
*                                                                                    *
*You should have received a copy of the GNU Lesser General Public                    *
*License along with this library; if not, write to the Free Software                 *
*Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA      *
**************************************************************************************
*/
#pragma once

#include <string>
#include <map>
#include <vector>

#include "../shared/geom.h"
#include "../EventManager.h"

/**
==========================
Manage all the entities of the world
Singleton
==========================
*/
template<class T>
class QuadTree;
class Scene;
class ICamera;
class IEntity;
class IWeapon;
class Player;

class EntityManager
{
public:
    /** Only allow one instance of the Entity Manager */
    static EntityManager* GetInstance() { return instance; }

    /** Update each entity */
    void Update(float dt, ICamera* cam);

    /** Remove the entity without deleting it */
    void RemoveWithoutDeleting(IEntity* ent);
    /** Deletes all the entities */
    void DeleteAllEntities();

    /** Get the Player */
    Player*   GetPlayer();
    
    /** Register the entity */
    void RegisterEntity( IEntity* ent, const std::string &name );
    /** Place the Entity */
    void PutInWorld( IEntity* ent );
    /** Find Entity by Name */
    IEntity* Find( const std::string &name );
    /** Find Entity by id */
    IEntity* Find( int id );
    /** Retrieve a Quadtree of Entities on the map */
    QuadTree<IEntity*>* GetEntityQuadTree() { return m_entityQuadTree; };

    /** Find the first entity in a given region */
    IEntity* FindInRegion( Rect &region, IEntity* ignoreMe = NULL );
    /** RayCast- Shoot a ray to see if it hits something, if so return
        the first Entity hit, else return NULL.
      */
    IEntity* CheckLineHit( const Vector2f &start, const Vector2f &end ); 

    /** How many entities are active */
    size_t Count() { return entities.size(); };

    /** HACK--How to register the Map with entities?
        Reference: Currently I register the scene
        when we load a new Scene, look at InGameStateView::LoadScene()
        with the EntityManager, this is horrible and NEEDS fixing.
      */
    void    SetScene(Scene* scene);
    Scene* GetScene() { return m_scene; };
private:
    EntityManager(void);
    /** Add the entity to the map */
    void AddEntity( IEntity* ent) {
        entities.push_back( ent );
    };
    /** Prune the entity List */
    void CleanDeadEntities();

    /** Move each entity that needs to be moved */
    bool Move(IEntity* ent, ICamera* cam, float deltaTime);

    /** Move X coord of an ent */
    float MoveX(IEntity *ent, float xmove, Vector2f &oldPosition, Scene* scene );
    /** Move Y coord of an ent */
    float MoveY(IEntity *ent, float ymove, Vector2f &oldPosition, Scene* scene );

    /** Check collision between entities */
    bool CheckCollision(IEntity* ent, const Vector2f &pos );
    // entity list
    typedef std::vector<IEntity* > type_ents;
    type_ents entities;

    // our instance
    static EntityManager *instance;
    // ids
    static unsigned int m_idcounter;

    // if the player has been created
    bool        m_playerCreated;

    // Get the player
    Player*     m_player;

    // it hurts me to write this
    // the current scene
    Scene*      m_scene;

    // quick list to all entities in the world
    QuadTree<IEntity*> *m_entityQuadTree;
public:
    virtual ~EntityManager(void);
};


/**
 * We Added/Removed this entity to the world,
 * so let anybody who cares know about it.
 */
struct EntityAdditionData : public IEventData
{
	EntityAdditionData( IEntity* ent ) : m_entity(ent) {};
	IEntity* m_entity;
	IEventData* Copy() { return new EntityAdditionData( m_entity ); };
    virtual ~EntityAdditionData() { /*std::cout << "Deleting entadd data\n";*/ };
};